home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1995 October / EnigmA AMIGA RUN 01 (1995)(G.R. Edizioni)(IT)[!][issue 1995-10][Aminet 7].iso / Aminet / comm / cnet / RRR_RH02.lha / Hydra / HydraCom5.lha / source / amiga.c < prev    next >
C/C++ Source or Header  |  1995-01-25  |  54KB  |  2,479 lines

  1. /*
  2. **    Amiga support module for HYDRA protocol sample implementation.
  3. **
  4. **    Written by    Olaf Barthel
  5. **            Brabeckstrasse 35
  6. **            D-30559 Hannover
  7. **
  8. **            eMail: olsen@sourcery.han.de
  9. **
  10. **    Freely distributable.
  11. */
  12.  
  13.     /* System includes. */
  14.  
  15. #include <intuition/intuitionbase.h>
  16.  
  17. #include <libraries/gadtools.h>
  18. #include <libraries/locale.h>
  19. #include <libraries/asl.h>
  20.  
  21. #include <graphics/gfxbase.h>
  22.  
  23. #include <utility/date.h>
  24.  
  25. #include <devices/conunit.h>
  26. #include <devices/serial.h>
  27. #include <devices/timer.h>
  28.  
  29. #include <hardware/cia.h>
  30.  
  31. #include <dos/dosextens.h>
  32. #include <dos/filehandler.h>
  33. #include <dos/dostags.h>
  34. #include <dos/dosasl.h>
  35.  
  36. #include <exec/memory.h>
  37.  
  38.     /* Correct a nasty bug in the prototypes. */
  39.  
  40. #define CheckIO foo21234
  41.  
  42. #include <clib/intuition_protos.h>
  43. #include <clib/gadtools_protos.h>
  44. #include <clib/graphics_protos.h>
  45. #include <clib/utility_protos.h>
  46. #include <clib/locale_protos.h>
  47. #include <clib/timer_protos.h>
  48. #include <clib/exec_protos.h>
  49. #include <clib/dos_protos.h>
  50. #include <clib/asl_protos.h>
  51. #include <clib/macros.h>
  52.  
  53. #include <errno.h>
  54.  
  55.     /* Get the CheckIO prototype right. */
  56.  
  57. #undef CheckIO
  58.  
  59. struct IORequest *CheckIO(struct IORequest *);
  60.  
  61. #include "Rendezvous.h"
  62.  
  63. #include "hydracom.h"
  64.  
  65.     /* Differenze between UTC and Amiga time. */
  66.  
  67. #define UTC_OFFSET    252482400
  68.  
  69.     /* Minimum of lines to reserve for local input. */
  70.  
  71. #define MIN_LINES    3
  72.  
  73.     /* Serial buffer size. */
  74.  
  75. #define BUFFER_SIZE    8192
  76.  
  77.     /* A handy macro. */
  78.  
  79. #define ClrSignal(s)    SetSignal(0,s)
  80.  
  81.     /* Signal masks. */
  82.  
  83. #define SIG_SERREAD    (1UL << ReadPort -> mp_SigBit)
  84. #define SIG_SERWRITE    (1UL << WritePort -> mp_SigBit)
  85. #define SIG_CONREAD    (1UL << ConsoleReadPort -> mp_SigBit)
  86. #define SIG_TIMER    (1UL << TimePort -> mp_SigBit)
  87. #define SIG_WINDOW    (1UL << LocalWindow -> UserPort -> mp_SigBit)
  88. #define SIG_HANDSHAKE    SIGF_SINGLE
  89. #define SIG_KILL    SIGBREAKF_CTRL_C
  90.  
  91.     /* A serial buffer structure. */
  92.  
  93. struct SerialBuffer
  94. {
  95.     struct IOExtSer    *SerialRequest;
  96.     UBYTE        *SerialBuffer,
  97.             *SerialIndex,
  98.             *SerialTop;
  99.     LONG         SerialSize,
  100.              SerialFilled;
  101.     BOOL         IsClone,
  102.              IsBusy;
  103. };
  104.  
  105.     /* Special rendezvous data. */
  106.  
  107. STATIC struct RendezvousData        *RendezvousData;
  108. STATIC struct RendezvousSemaphore    *RendezvousSemaphore;
  109.  
  110.     /* Library bases. */
  111.  
  112. struct IntuitionBase    *IntuitionBase;
  113. struct GfxBase        *GfxBase;
  114. struct LocaleBase    *LocaleBase;
  115. struct Library        *GadToolsBase,
  116.             *UtilityBase,
  117.             *TimerBase,
  118.             *AslBase;
  119.  
  120.     /* Timer data. */
  121.  
  122. struct MsgPort        *TimePort;
  123. struct timerequest    *TimeRequest;
  124.  
  125.     /* Serial data. */
  126.  
  127. struct MsgPort        *ReadPort,
  128.             *WritePort;
  129.  
  130. struct SerialBuffer    *ThisBuffer,
  131.             *NextBuffer,
  132.             *ReadBuffer;
  133.  
  134.     /* Console data. */
  135.  
  136. struct Window        *FileWindow,
  137.             *RemoteWindow,
  138.             *LocalWindow,
  139.             *LogWindow;
  140.  
  141. struct MsgPort        *ConsoleWritePort,
  142.             *ConsoleReadPort;
  143. struct IOStdReq        *ConsoleReadRequest;
  144. UBYTE             ConsoleChar;
  145. BOOL             ConsoleReady = FALSE,
  146.              WindowReady = FALSE;
  147.  
  148. struct IOStdReq        *FileRequest,
  149.             *RemoteRequest,
  150.             *LocalRequest,
  151.             *LogRequest;
  152.  
  153.     /* DOS Data. */
  154.  
  155. struct Process        *ThisProcess;
  156. APTR             OldPtr;
  157.  
  158. struct AnchorPath    *Anchor;
  159. BOOL             AnchorUsed = FALSE;
  160.  
  161.     /* File requester data. */
  162.  
  163. struct Process        *FileRequesterProcess;
  164. struct MsgPort        *FileRequesterPort;
  165.  
  166.     /* Screen data. */
  167.  
  168. struct Screen        *PublicScreen,
  169.             *Screen;
  170.  
  171.     /* Menu data. */
  172.  
  173. APTR             VisualInfo;
  174. struct Menu        *Menu;
  175.  
  176. struct NewMenu MenuTemplate[] =
  177. {
  178.     { NM_TITLE, "Project",             0 ,    0,    0,    (APTR)0},
  179.     {  NM_ITEM, "Toggle chat",        "C",    0,    0,    (APTR)Alt_C},
  180.     {  NM_ITEM, NM_BARLABEL,         0 ,    0,    0,    (APTR)0},
  181.     {  NM_ITEM, "Hang up",            "H",    0,    0,    (APTR)Alt_H},
  182.     {  NM_ITEM, "Toggle duplex",        "E",    0,    0,    (APTR)Alt_E},
  183.     {  NM_ITEM, "Toggle 7 bits/8 bits",    "B",    0,    0,    (APTR)Alt_B},
  184.     {  NM_ITEM, NM_BARLABEL,         0 ,    0,    0,    (APTR)0},
  185.     {  NM_ITEM, "Start upload",        "U",    0,    0,    (APTR)PgUp},
  186.     {  NM_ITEM, "Start download",        "D",    0,    0,    (APTR)PgDn},
  187.     {  NM_ITEM, NM_BARLABEL,         0 ,    0,    0,    (APTR)0},
  188.     {  NM_ITEM, "Abort Hydra session",    ".",    0,    0,    (APTR)Esc},
  189.     {  NM_ITEM, NM_BARLABEL,         0 ,    0,    0,    (APTR)0},
  190.     {  NM_ITEM, "Exit HydraCom",        "Q",    0,    0,    (APTR)Alt_X},
  191.     { NM_END,   0,                 0 ,    0,    0,    (APTR)0}
  192. };
  193.  
  194.     /* Time data. */
  195.  
  196. LONG             GMT_Offset = UTC_OFFSET;
  197.  
  198.     /* Version ID. */
  199.  
  200. STRPTR VersionTag = "$VER: hydracom 1.0r5 (25.1.95)\r\n";
  201.  
  202.     /* UpdateTime(struct timeval *Now):
  203.      *
  204.      *    Get the current time and/or update the current
  205.      *    time offset data.
  206.      */
  207.  
  208. STATIC VOID __regargs
  209. UpdateTime(struct timeval *Now)
  210. {
  211.     if(Now)
  212.         Now -> tv_secs = Now -> tv_micro = 0;
  213.  
  214.     if(TimePort = CreateMsgPort())
  215.     {
  216.         if(TimeRequest = (struct timerequest *)CreateIORequest(TimePort,sizeof(struct timerequest)))
  217.         {
  218.             if(!OpenDevice(TIMERNAME,UNIT_VBLANK,TimeRequest,NULL))
  219.             {
  220.                 TimerBase = (struct Library *)TimeRequest -> tr_node . io_Device;
  221.  
  222.                 if(LocaleBase = (struct LocaleBase *)OpenLibrary("locale.library",38))
  223.                 {
  224.                     struct Locale *Locale;
  225.  
  226.                     if(Locale = OpenLocale(NULL))
  227.                     {
  228.                         GMT_Offset = 60 * Locale -> loc_GMTOffset + UTC_OFFSET;
  229.  
  230.                         CloseLocale(Locale);
  231.                     }
  232.  
  233.                     CloseLibrary(LocaleBase);
  234.  
  235.                     LocaleBase = NULL;
  236.                 }
  237.  
  238.                 if(Now)
  239.                     GetSysTime(Now);
  240.  
  241.                 TimerBase = NULL;
  242.  
  243.                 CloseDevice(TimeRequest);
  244.             }
  245.  
  246.             DeleteIORequest(TimeRequest);
  247.  
  248.             TimeRequest = NULL;
  249.         }
  250.  
  251.         DeleteMsgPort(TimePort);
  252.  
  253.         TimePort = NULL;
  254.     }
  255. }
  256.  
  257.     /* FileRequestEntry(VOID):
  258.      *
  259.      *    Asynchronous file request process entry.
  260.      */
  261.  
  262. STATIC VOID __saveds
  263. FileRequestEntry(VOID)
  264. {
  265.     struct FileRequester *FileRequester;
  266.  
  267.     if(FileRequester = (struct FileRequester *)AllocAslRequestTags(ASL_FileRequest,
  268.         ASLFR_TitleText,    "Select file(s) to upload",
  269.         ASLFR_InitialPattern,    "#?",
  270.         ASLFR_Flags1,        FRF_PRIVATEIDCMP | FRF_DOMULTISELECT | FRF_DOPATTERNS,
  271.     TAG_DONE))
  272.     {
  273.         if(FileRequesterPort = CreateMsgPort())
  274.         {
  275.             struct Message    *Message;
  276.             ULONG         Signals;
  277.             BOOL         Done = FALSE;
  278.  
  279.             FileRequesterProcess = (struct Process *)FindTask(NULL);
  280.  
  281.             Signal(ThisProcess,SIG_HANDSHAKE);
  282.  
  283.             do
  284.             {
  285.                 Signals = Wait((1L << FileRequesterPort -> mp_SigBit) | SIG_KILL);
  286.  
  287.                 if(Signals & (1L << FileRequesterPort -> mp_SigBit))
  288.                 {
  289.                     LONG MaxLen;
  290.  
  291.                     while(Message = GetMsg(FileRequesterPort))
  292.                     {
  293.                         MaxLen = (LONG)Message -> mn_Node . ln_Name;
  294.  
  295.                         if(AslRequestTags(FileRequester,
  296.                             ASLFR_Window,        LocalWindow,
  297.                             ASLFR_SleepWindow,    TRUE,
  298.                         TAG_DONE))
  299.                         {
  300.                             if(FileRequester -> fr_NumArgs > 0)
  301.                             {
  302.                                 UBYTE     LocalBuffer[256];
  303.                                 char    *String;
  304.                                 LONG     Len,Count,i;
  305.  
  306.                                 for(i = Len = 0 ; i < FileRequester -> fr_NumArgs ; i++)
  307.                                 {
  308.                                     if(FileRequester -> fr_ArgList[i] . wa_Lock)
  309.                                     {
  310.                                         if(NameFromLock(FileRequester -> fr_ArgList[i] . wa_Lock,LocalBuffer,256))
  311.                                             Len += strlen(LocalBuffer) + 1;
  312.                                     }
  313.                                     else
  314.                                         Len += strlen(FileRequester -> fr_Drawer) + 1;
  315.  
  316.                                     Len += strlen(FileRequester -> fr_ArgList[i] . wa_Name) + 1;
  317.                                 }
  318.  
  319.                                 Len++;
  320.  
  321.                                 if(String = AllocVec(Len,MEMF_ANY))
  322.                                 {
  323.                                     *String = 0;
  324.  
  325.                                     for(i = Count = 0 ; Count < MaxLen && i < FileRequester -> fr_NumArgs ; i++)
  326.                                     {
  327.                                         if(FileRequester -> fr_ArgList[i] . wa_Lock)
  328.                                         {
  329.                                             if(NameFromLock(FileRequester -> fr_ArgList[i] . wa_Lock,LocalBuffer,256))
  330.                                             {
  331.                                                 if(AddPart(LocalBuffer,FileRequester -> fr_ArgList[i] . wa_Name,256))
  332.                                                 {
  333.                                                     if(Count + strlen(LocalBuffer) < MaxLen)
  334.                                                     {
  335.                                                         strcat(String,LocalBuffer);
  336.  
  337.                                                         Count += strlen(LocalBuffer);
  338.                                                     }
  339.                                                     else
  340.                                                         break;
  341.                                                 }
  342.                                             }
  343.                                         }
  344.                                         else
  345.                                         {
  346.                                             strcpy(LocalBuffer,FileRequester -> fr_Drawer);
  347.  
  348.                                             if(AddPart(LocalBuffer,FileRequester -> fr_ArgList[i] . wa_Name,256))
  349.                                             {
  350.                                                 if(Count + strlen(LocalBuffer) < MaxLen)
  351.                                                 {
  352.                                                     strcat(String,LocalBuffer);
  353.  
  354.                                                     Count += strlen(LocalBuffer);
  355.                                                 }
  356.                                                 else
  357.                                                     break;
  358.                                             }
  359.                                         }
  360.  
  361.                                         if(i != FileRequester -> fr_NumArgs - 1)
  362.                                         {
  363.                                             strcat(String," ");
  364.                                             Count++;
  365.                                         }
  366.                                     }
  367.  
  368.                                     Message -> mn_Node . ln_Name = String;
  369.  
  370.                                     ReplyMsg(Message);
  371.  
  372.                                     Message = NULL;
  373.                                 }
  374.                             }
  375.                             else
  376.                             {
  377.                                 if(FileRequester -> fr_File[0])
  378.                                 {
  379.                                     LONG Len;
  380.  
  381.                                     Len = strlen(FileRequester -> fr_Drawer) + strlen(FileRequester -> fr_File) + 2;
  382.  
  383.                                     if(Len <= MaxLen)
  384.                                     {
  385.                                         char *String;
  386.  
  387.                                         if(String = AllocVec(Len,MEMF_ANY))
  388.                                         {
  389.                                             strcpy(String,FileRequester -> fr_Drawer);
  390.  
  391.                                             if(AddPart(String,FileRequester -> fr_File,Len))
  392.                                             {
  393.                                                 Message -> mn_Node . ln_Name = String;
  394.  
  395.                                                 ReplyMsg(Message);
  396.  
  397.                                                 Message = NULL;
  398.                                             }
  399.                                             else
  400.                                                 FreeVec(String);
  401.                                         }
  402.                                     }
  403.                                 }
  404.                             }
  405.                         }
  406.  
  407.                         if(Message)
  408.                         {
  409.                             Message -> mn_Node . ln_Name = NULL;
  410.  
  411.                             ReplyMsg(Message);
  412.                         }
  413.                     }
  414.                 }
  415.  
  416.                 if(Signals & SIG_KILL)
  417.                     Done = TRUE;
  418.             }
  419.             while(!Done);
  420.  
  421.             while(Message = GetMsg(FileRequesterPort))
  422.             {
  423.                 Message -> mn_Node . ln_Name = NULL;
  424.  
  425.                 ReplyMsg(Message);
  426.             }
  427.  
  428.             DeleteMsgPort(FileRequesterPort);
  429.         }
  430.  
  431.         FreeAslRequest(FileRequester);
  432.     }
  433.  
  434.     Forbid();
  435.  
  436.     FileRequesterProcess = NULL;
  437.  
  438.     Signal(ThisProcess,SIG_HANDSHAKE);
  439. }
  440.  
  441.     /* GetFiles(char *Buffer,int MaxLen):
  442.      *
  443.      *    Get a list of file names, asynchronously please.
  444.      */
  445.  
  446. char *
  447. GetFiles(char *Buffer,int MaxLen)
  448. {
  449.     struct MsgPort    *ReplyPort;
  450.     char        *Result = NULL;
  451.  
  452.     if(ReplyPort = CreateMsgPort())
  453.     {
  454.         struct Message *Message;
  455.  
  456.         if(Message = AllocVec(sizeof(struct Message),MEMF_ANY | MEMF_CLEAR))
  457.         {
  458.             Message -> mn_Length        = sizeof(struct Message);
  459.             Message -> mn_ReplyPort        = ReplyPort;
  460.             Message -> mn_Node . ln_Name    = (STRPTR)MaxLen;
  461.  
  462.             PutMsg(FileRequesterPort,Message);
  463.  
  464.             FOREVER
  465.             {
  466.                 if(SetSignal(0,(1L << ReplyPort -> mp_SigBit)) & (1L << ReplyPort -> mp_SigBit))
  467.                 {
  468.                     GetMsg(ReplyPort);
  469.  
  470.                     break;
  471.                 }
  472.  
  473.                 sys_idle();
  474.             }
  475.  
  476.             if(Message -> mn_Node . ln_Name)
  477.             {
  478.                 strcpy(Buffer,Message -> mn_Node . ln_Name);
  479.  
  480.                 FreeVec(Message -> mn_Node . ln_Name);
  481.  
  482.                 Result = Buffer;
  483.             }
  484.  
  485.             FreeVec(Message);
  486.         }
  487.  
  488.         DeleteMsgPort(ReplyPort);
  489.     }
  490.  
  491.     return(Result);
  492. }
  493.  
  494.     /* OpenConsole():
  495.      *
  496.      *    Open a console window.
  497.      */
  498.  
  499. STATIC BOOL __inline
  500. OpenConsole(struct Screen *Screen,LONG Top,LONG Height,STRPTR Title,BOOL Resize,struct Window **WindowPtr,struct IOStdReq **ConsolePtr)
  501. {
  502.     struct Window *Window;
  503.  
  504.     if(Window = OpenWindowTags(NULL,
  505.         WA_Left,        0,
  506.         WA_Top,            Top,
  507.         WA_Width,        Screen -> Width,
  508.         WA_Height,        Height,
  509.         WA_Title,        Title,
  510.         WA_SimpleRefresh,    TRUE,
  511.         WA_DepthGadget,        TRUE,
  512.         WA_DragBar,        TRUE,
  513.         WA_SizeGadget,        Resize,
  514.         WA_SizeBRight,        TRUE,
  515.         WA_CustomScreen,    Screen,
  516.         WA_RMBTrap,        TRUE,
  517.         WA_NewLookMenus,    TRUE,
  518.     TAG_DONE))
  519.     {
  520.         struct IOStdReq *ConsoleRequest;
  521.  
  522.         if(Window -> RPort -> Font -> tf_Flags & FPF_PROPORTIONAL)
  523.             SetFont(Window -> RPort,GfxBase -> DefaultFont);
  524.  
  525.         if(ConsoleRequest = (struct IOStdReq *)CreateIORequest(ConsoleWritePort,sizeof(struct IOStdReq)))
  526.         {
  527.             ConsoleRequest -> io_Data = Window;
  528.  
  529.             if(!OpenDevice("console.device",CONU_CHARMAP,ConsoleRequest,CONFLAG_DEFAULT))
  530.             {
  531.                 WindowLimits(Window,Window -> BorderLeft + 10 * Window -> RPort -> Font -> tf_XSize * 10 + Window -> BorderRight,Window -> BorderTop + 2 * Window -> RPort -> Font -> tf_YSize + Window -> BorderBottom,Screen -> Width,Screen -> Height);
  532.  
  533.                     /* Turn off the cursor. */
  534.  
  535.                 ConPrintf(ConsoleRequest,"\033[0 p");
  536.  
  537.                 *WindowPtr    = Window;
  538.                 *ConsolePtr    = ConsoleRequest;
  539.  
  540.                 return(TRUE);
  541.             }
  542.  
  543.             DeleteIORequest(ConsoleRequest);
  544.         }
  545.  
  546.         CloseWindow(Window);
  547.     }
  548.  
  549.     return(FALSE);
  550. }
  551.  
  552.     /* CloseConsole():
  553.      *
  554.      *    Close a console window.
  555.      */
  556.  
  557. STATIC VOID __inline
  558. CloseConsole(struct Window **WindowPtr,struct IOStdReq **ConsolePtr)
  559. {
  560.     if(*ConsolePtr)
  561.     {
  562.         CloseDevice(*ConsolePtr);
  563.  
  564.         DeleteIORequest(*ConsolePtr);
  565.  
  566.         *ConsolePtr = NULL;
  567.     }
  568.  
  569.     if(*WindowPtr)
  570.     {
  571.         CloseWindow(*WindowPtr);
  572.  
  573.         *WindowPtr = NULL;
  574.     }
  575. }
  576.  
  577.     /* CloneSerialBuffer():
  578.      *
  579.      *    Clone a SerialBuffer structure.
  580.      */
  581.  
  582. STATIC struct SerialBuffer * __regargs
  583. CloneSerialBuffer(struct SerialBuffer *Source,struct MsgPort *MsgPort)
  584. {
  585.     struct SerialBuffer *Buffer;
  586.  
  587.     if(Buffer = (struct SerialBuffer *)AllocVec(sizeof(struct SerialBuffer) + Source -> SerialSize,MEMF_ANY | MEMF_PUBLIC))
  588.     {
  589.         Buffer -> SerialBuffer    = Buffer -> SerialIndex = (UBYTE *)(Buffer + 1);
  590.         Buffer -> SerialFilled    = 0;
  591.         Buffer -> SerialTop    = Buffer -> SerialBuffer + Source -> SerialSize;
  592.         Buffer -> SerialSize    = Source -> SerialSize;
  593.         Buffer -> IsClone    = TRUE;
  594.         Buffer -> IsBusy    = FALSE;
  595.  
  596.         if(Buffer -> SerialRequest = (struct IOExtSer *)AllocVec(sizeof(struct IOExtSer),MEMF_ANY | MEMF_PUBLIC))
  597.         {
  598.             CopyMem(Source -> SerialRequest,Buffer -> SerialRequest,sizeof(struct IOExtSer));
  599.  
  600.             Buffer -> SerialRequest -> IOSer . io_Message . mn_ReplyPort = MsgPort;
  601.  
  602.             return(Buffer);
  603.         }
  604.         else
  605.             cprint("Could not create serial request\n");
  606.  
  607.         FreeVec(Buffer);
  608.     }
  609.     else
  610.         cprint("Could not create serial buffer\n");
  611.  
  612.     return(NULL);
  613. }
  614.  
  615.     /* DeleteSerialBuffer():
  616.      *
  617.      *    Delete a SerialBuffer structure.
  618.      */
  619.  
  620. STATIC VOID __regargs
  621. DeleteSerialBuffer(struct SerialBuffer *Buffer)
  622. {
  623.     if(Buffer)
  624.     {
  625.         if(Buffer -> IsBusy)
  626.         {
  627.             if(!CheckIO(Buffer -> SerialRequest))
  628.                 AbortIO(Buffer -> SerialRequest);
  629.  
  630.             WaitIO(Buffer -> SerialRequest);
  631.         }
  632.  
  633.         if(Buffer -> IsClone)
  634.             FreeVec(Buffer -> SerialRequest);
  635.         else
  636.         {
  637.             CloseDevice(Buffer -> SerialRequest);
  638.  
  639.             DeleteIORequest(Buffer -> SerialRequest);
  640.         }
  641.  
  642.         FreeVec(Buffer);
  643.     }
  644. }
  645.  
  646.     /* CreateSerialBuffer():
  647.      *
  648.      *    Create a serial buffer structure.
  649.      */
  650.  
  651. STATIC struct SerialBuffer * __regargs
  652. CreateSerialBuffer(STRPTR Device,LONG Unit,LONG Size,struct MsgPort *MsgPort)
  653. {
  654.     struct SerialBuffer *Buffer;
  655.  
  656.     if(Buffer = (struct SerialBuffer *)AllocVec(sizeof(struct SerialBuffer) + Size,MEMF_ANY | MEMF_PUBLIC))
  657.     {
  658.         Buffer -> SerialBuffer    = Buffer -> SerialIndex = (UBYTE *)(Buffer + 1);
  659.         Buffer -> SerialFilled    = 0;
  660.         Buffer -> SerialTop    = Buffer -> SerialBuffer + Size;
  661.         Buffer -> SerialSize    = Size;
  662.         Buffer -> IsClone    = FALSE;
  663.         Buffer -> IsBusy    = FALSE;
  664.  
  665.         if(Buffer -> SerialRequest = (struct IOExtSer *)CreateIORequest(MsgPort,sizeof(struct IOExtSer)))
  666.         {
  667.             Buffer -> SerialRequest -> io_SerFlags = SERF_SHARED;
  668.  
  669.             if(!OpenDevice(Device,Unit,Buffer -> SerialRequest,NULL))
  670.                 return(Buffer);
  671.             else
  672.             {
  673.                 cprint("Could not open \"%s\", unit %d\n",Device,Unit);
  674.  
  675.                 DeleteIORequest(Buffer -> SerialRequest);
  676.             }
  677.         }
  678.         else
  679.             cprint("Could not create serial request\n");
  680.  
  681.         FreeVec(Buffer);
  682.     }
  683.     else
  684.         cprint("Could not create serial buffer\n");
  685.  
  686.     return(NULL);
  687. }
  688.  
  689.     /* OpenAll():
  690.      *
  691.      *    Allocate all the resources required.
  692.      */
  693.  
  694. STATIC BOOL
  695. OpenAll(STRPTR Device,LONG Unit)
  696. {
  697.     LONG Top,Lines,BorderSize,FontSize,ExtraLines,RemainingLines,TotalHeight;
  698.     UWORD Pens = (UWORD)~0;
  699.  
  700.     ThisProcess = (struct Process *)FindTask(NULL);
  701.  
  702.     if(!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",37)))
  703.     {
  704.         cprint("Could not open intuition.library v37\n");
  705.  
  706.         return(FALSE);
  707.     }
  708.  
  709.     if(!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",37)))
  710.     {
  711.         cprint("Could not open graphics.library v37\n");
  712.  
  713.         return(FALSE);
  714.     }
  715.  
  716.     if(!(GadToolsBase = OpenLibrary("gadtools.library",37)))
  717.     {
  718.         cprint("Could not open gadtools.library v37\n");
  719.  
  720.         return(FALSE);
  721.     }
  722.  
  723.     if(!(UtilityBase = OpenLibrary("utility.library",37)))
  724.     {
  725.         cprint("Could not open utility.library v37\n");
  726.  
  727.         return(FALSE);
  728.     }
  729.  
  730.     if(!(AslBase = OpenLibrary("asl.library",37)))
  731.     {
  732.         cprint("Could not open asl.library v37\n");
  733.  
  734.         return(FALSE);
  735.     }
  736.  
  737.     if(LocaleBase = (struct LocaleBase *)OpenLibrary("locale.library",38))
  738.     {
  739.         struct Locale *Locale;
  740.  
  741.         if(Locale = OpenLocale(NULL))
  742.         {
  743.             GMT_Offset = 60 * Locale -> loc_GMTOffset + UTC_OFFSET;
  744.  
  745.             CloseLocale(Locale);
  746.         }
  747.  
  748.         CloseLibrary(LocaleBase);
  749.     }
  750.  
  751.     Forbid();
  752.  
  753.     if(CreateNewProcTags(
  754.         NP_Name,    "HydraCom Filerequester Process",
  755.         NP_WindowPtr,    -1,
  756.         NP_Entry,    FileRequestEntry,
  757.     TAG_DONE))
  758.     {
  759.         ClrSignal(SIG_HANDSHAKE);
  760.  
  761.         Wait(SIG_HANDSHAKE);
  762.     }
  763.  
  764.     Permit();
  765.  
  766.     if(!FileRequesterProcess)
  767.     {
  768.         cprint("Could not create file requester process\n");
  769.  
  770.         return(FALSE);
  771.     }
  772.  
  773.     if(!(TimePort = CreateMsgPort()))
  774.     {
  775.         cprint("Could not create timer port\n");
  776.  
  777.         return(FALSE);
  778.     }
  779.  
  780.     if(!(TimeRequest = (struct timerequest *)CreateIORequest(TimePort,sizeof(struct timerequest))))
  781.     {
  782.         cprint("Could not create timer request\n");
  783.  
  784.         return(FALSE);
  785.     }
  786.  
  787.     if(OpenDevice(TIMERNAME,UNIT_VBLANK,TimeRequest,NULL))
  788.     {
  789.         cprint("Could not open timer\n");
  790.  
  791.         return(FALSE);
  792.     }
  793.  
  794.     TimerBase = (struct Library *)TimeRequest -> tr_node . io_Device;
  795.  
  796.     if(!(Anchor = (struct AnchorPath *)AllocVec(sizeof(struct AnchorPath) + 512,MEMF_ANY | MEMF_CLEAR)))
  797.     {
  798.         cprint("Could not allocate pattern matching buffe\n");
  799.  
  800.         return(FALSE);
  801.     }
  802.  
  803.     Anchor -> ap_Strlen = 512;
  804.  
  805.     if(!(ReadPort = CreateMsgPort()))
  806.     {
  807.         cprint("Could not create serial read port\n");
  808.  
  809.         return(FALSE);
  810.     }
  811.  
  812.     if(!(WritePort = CreateMsgPort()))
  813.     {
  814.         cprint("Could not create serial write port\n");
  815.  
  816.         return(FALSE);
  817.     }
  818.  
  819.     Forbid();
  820.  
  821.     if(RendezvousSemaphore = (struct RendezvousSemaphore *)FindSemaphore(Device))
  822.     {
  823.         ObtainSemaphore(RendezvousSemaphore);
  824.  
  825.         if(!(RendezvousData = (*RendezvousSemaphore -> rs_Login)(ReadPort,WritePort,NULL)))
  826.         {
  827.             Permit();
  828.  
  829.             ReleaseSemaphore(RendezvousSemaphore);
  830.  
  831.             RendezvousSemaphore = NULL;
  832.  
  833.             cprint("Could not link to `term' port \"%s\"\n",Device);
  834.  
  835.             return(FALSE);
  836.         }
  837.     }
  838.  
  839.     Permit();
  840.  
  841.     if(!(ConsoleReadPort = CreateMsgPort()))
  842.     {
  843.         cprint("Could not create console read port\n");
  844.  
  845.         return(FALSE);
  846.     }
  847.  
  848.     if(!(ConsoleWritePort = CreateMsgPort()))
  849.     {
  850.         cprint("Could not create console write port\n");
  851.  
  852.         return(FALSE);
  853.     }
  854.  
  855.     if(!(ConsoleReadRequest = (struct IOStdReq *)AllocVec(sizeof(struct IOStdReq),MEMF_ANY | MEMF_PUBLIC | MEMF_CLEAR)))
  856.     {
  857.         cprint("Could not create console read request\n");
  858.  
  859.         return(FALSE);
  860.     }
  861.  
  862.     if(!RendezvousData)
  863.     {
  864.         if(!(ReadBuffer = CreateSerialBuffer(Device,Unit,BUFFER_SIZE,ReadPort)))
  865.             return(FALSE);
  866.     }
  867.     else
  868.     {
  869.         if(ReadBuffer = (struct SerialBuffer *)AllocVec(sizeof(struct SerialBuffer) + BUFFER_SIZE,MEMF_ANY | MEMF_PUBLIC))
  870.         {
  871.             ReadBuffer -> SerialBuffer    = ReadBuffer -> SerialIndex = (UBYTE *)(ReadBuffer + 1);
  872.             ReadBuffer -> SerialFilled    = 0;
  873.             ReadBuffer -> SerialTop        = ReadBuffer -> SerialBuffer + BUFFER_SIZE;
  874.             ReadBuffer -> SerialSize    = BUFFER_SIZE;
  875.             ReadBuffer -> IsClone        = TRUE;
  876.             ReadBuffer -> IsBusy        = FALSE;
  877.             ReadBuffer -> SerialRequest    = &RendezvousData -> rd_ReadRequest;
  878.         }
  879.         else
  880.         {
  881.             cprint("Could not create serial ReadBuffer\n");
  882.  
  883.             return(FALSE);
  884.         }
  885.     }
  886.  
  887.     if(!(ThisBuffer = CloneSerialBuffer(ReadBuffer,WritePort)))
  888.         return(FALSE);
  889.  
  890.     if(!(NextBuffer = CloneSerialBuffer(ReadBuffer,WritePort)))
  891.         return(FALSE);
  892.  
  893.     if(!(PublicScreen = LockPubScreen(NULL)))
  894.     {
  895.         cprint("Could not find default public screen\n");
  896.  
  897.         return(FALSE);
  898.     }
  899.  
  900.     if(RendezvousData)
  901.     {
  902.         if(!(Screen = RendezvousData -> rd_Screen))
  903.             Screen = PublicScreen;
  904.     }
  905.     else
  906.     {
  907.         if(!(Screen = OpenScreenTags(NULL,
  908.             SA_DisplayID,    GetVPModeID(&PublicScreen -> ViewPort),
  909.             SA_Overscan,    OSCAN_TEXT,
  910.             SA_Depth,    2,
  911.             SA_Title,    PRGNAME " " VERSION " " HC_OS " Amiga rev 5, ported by Olaf `Olsen' Barthel",
  912.             SA_Behind,    TRUE,
  913.             SA_SysFont,    1,
  914.             SA_Pens,    &Pens,
  915.         TAG_DONE)))
  916.         {
  917.             cprint("Could not open screen\n");
  918.  
  919.             return(FALSE);
  920.         }
  921.     }
  922.  
  923.     if(!(VisualInfo = GetVisualInfo(Screen,TAG_DONE)))
  924.     {
  925.         cprint("Could not obtain screen visual info\n");
  926.  
  927.         return(FALSE);
  928.     }
  929.  
  930.     if(!(Menu = CreateMenus(MenuTemplate,TAG_DONE)))
  931.     {
  932.         cprint("Could not create menus\n");
  933.  
  934.         return(FALSE);
  935.     }
  936.  
  937.     if(!LayoutMenus(Menu,VisualInfo,
  938.         GTMN_TextAttr,        Screen -> Font,
  939.         GTMN_NewLookMenus,    TRUE,
  940.     TAG_DONE))
  941.     {
  942.         cprint("Could not layout menus\n");
  943.  
  944.         return(FALSE);
  945.     }
  946.  
  947.     Top        = Screen -> BarHeight + 1;
  948.     BorderSize    = Screen -> WBorTop + Screen -> Font -> ta_YSize + 1 + Screen -> WBorBottom;
  949.     FontSize    = GfxBase -> DefaultFont -> tf_YSize;
  950.     TotalHeight    = Screen -> Height - Top;
  951.     Lines        = (TotalHeight - 3 - 4 * BorderSize) / FontSize;
  952.     ExtraLines    = Lines > MIN_LINES ? (Lines - MIN_LINES) / 3 : 0;
  953.     RemainingLines    = Lines > MIN_LINES + ExtraLines * 3 ? Lines - (MIN_LINES + ExtraLines * 3) : 0;
  954.  
  955.     if(Lines < MIN_LINES)
  956.     {
  957.         cprint("Screen size too small (need at least %d text lines, can get only %d)\n",MIN_LINES,Lines);
  958.  
  959.         return(FALSE);
  960.     }
  961.  
  962.     if(!OpenConsole(Screen,Top,BorderSize + (6 + ExtraLines) * FontSize,"Log",TRUE,&LogWindow,&LogRequest))
  963.     {
  964.         cprint("Could not open console window #1\n");
  965.  
  966.         return(FALSE);
  967.     }
  968.  
  969.     TotalHeight    -= LogWindow -> Height + 1;
  970.     Top        += LogWindow -> Height + 1;
  971.  
  972.     if(!OpenConsole(Screen,Top,BorderSize + 2 * FontSize,"File",FALSE,&FileWindow,&FileRequest))
  973.     {
  974.         cprint("Could not open console window #2\n");
  975.  
  976.         return(FALSE);
  977.     }
  978.  
  979.     TotalHeight    -= FileWindow -> Height + 1;
  980.     Top        += FileWindow -> Height + 1;
  981.  
  982.     if(!OpenConsole(Screen,Top,BorderSize + (8 + RemainingLines) * FontSize,"Remote",TRUE,&RemoteWindow,&RemoteRequest))
  983.     {
  984.         cprint("Could not open console window #3\n");
  985.  
  986.         return(FALSE);
  987.     }
  988.  
  989.     TotalHeight    -= RemoteWindow -> Height + 1;
  990.     Top        += RemoteWindow -> Height + 1;
  991.  
  992.     if(!OpenConsole(Screen,Top,TotalHeight,"Local (Press [Amiga+C] to start/end chat mode, [Esc] to abort Hydra session)",TRUE,&LocalWindow,&LocalRequest))
  993.     {
  994.         cprint("Could not open console window #4\n");
  995.  
  996.         return(FALSE);
  997.     }
  998.  
  999.     SetMenuStrip(LocalWindow,Menu);
  1000.  
  1001.     if(!ModifyIDCMP(LocalWindow,IDCMP_MENUPICK))
  1002.     {
  1003.         cprint("Could not modify IDCMP flags\n");
  1004.  
  1005.         return(FALSE);
  1006.     }
  1007.  
  1008.     LocalWindow -> Flags &= ~WFLG_RMBTRAP;
  1009.  
  1010.     CopyMem(LocalRequest,ConsoleReadRequest,sizeof(struct IOStdReq));
  1011.  
  1012.     ConsoleReadRequest -> io_Message . mn_ReplyPort = ConsoleReadPort;
  1013.  
  1014.         /* Turn the cursors back on. */
  1015.  
  1016.     ConPrintf(LocalRequest,"\33[ p");
  1017.     ConPrintf(RemoteRequest,"\33[ p");
  1018.  
  1019.     ConsoleReadRequest -> io_Command    = CMD_READ;
  1020.     ConsoleReadRequest -> io_Data        = &ConsoleChar;
  1021.     ConsoleReadRequest -> io_Length        = 1;
  1022.  
  1023.     ClrSignal(SIG_CONREAD);
  1024.     SendIO(ConsoleReadRequest);
  1025.  
  1026.     OldPtr = ThisProcess -> pr_WindowPtr;
  1027.  
  1028.     ThisProcess -> pr_WindowPtr = (APTR)LocalWindow;
  1029.  
  1030.     ScreenToFront(Screen);
  1031.  
  1032.     ActivateWindow(LocalWindow);
  1033.  
  1034.     UnlockPubScreen(NULL,PublicScreen);
  1035.  
  1036.     PublicScreen = NULL;
  1037.  
  1038.     return(TRUE);
  1039. }
  1040.  
  1041.     /* CloseAll():
  1042.      *
  1043.      *    Close all the resources.
  1044.      */
  1045.  
  1046. STATIC VOID
  1047. CloseAll(VOID)
  1048. {
  1049.     if(FileRequesterProcess)
  1050.     {
  1051.         Forbid();
  1052.  
  1053.         ClrSignal(SIG_HANDSHAKE);
  1054.  
  1055.         Signal(FileRequesterProcess,SIG_KILL);
  1056.  
  1057.         Wait(SIG_HANDSHAKE);
  1058.  
  1059.         Permit();
  1060.     }
  1061.  
  1062.     if(LocalWindow)
  1063.         ClearMenuStrip(LocalWindow);
  1064.  
  1065.     if(Menu)
  1066.         FreeMenus(Menu);
  1067.  
  1068.     if(VisualInfo)
  1069.         FreeVisualInfo(VisualInfo);
  1070.  
  1071.     if(AnchorUsed)
  1072.         MatchEnd(Anchor);
  1073.  
  1074.     if(Anchor)
  1075.         FreeVec(Anchor);
  1076.  
  1077.     if(ThisProcess)
  1078.         ThisProcess -> pr_WindowPtr = OldPtr;
  1079.  
  1080.     if(ConsoleReadRequest)
  1081.     {
  1082.         if(ConsoleReadRequest -> io_Device)
  1083.         {
  1084.             if(!CheckIO(ConsoleReadRequest))
  1085.                 AbortIO(ConsoleReadRequest);
  1086.  
  1087.             WaitIO(ConsoleReadRequest);
  1088.         }
  1089.  
  1090.         FreeVec(ConsoleReadRequest);
  1091.     }
  1092.  
  1093.     CloseConsole(&LocalWindow,&LocalRequest);
  1094.     CloseConsole(&RemoteWindow,&RemoteRequest);
  1095.     CloseConsole(&FileWindow,&FileRequest);
  1096.     CloseConsole(&LogWindow,&LogRequest);
  1097.  
  1098.     if(!RendezvousData && Screen)
  1099.         CloseScreen(Screen);
  1100.  
  1101.     if(PublicScreen)
  1102.         UnlockPubScreen(NULL,PublicScreen);
  1103.  
  1104.     DeleteSerialBuffer(NextBuffer);
  1105.     DeleteSerialBuffer(ThisBuffer);
  1106.  
  1107.     if(RendezvousData)
  1108.     {
  1109.         if(ReadBuffer -> IsBusy)
  1110.         {
  1111.             if(!CheckIO(ReadBuffer -> SerialRequest))
  1112.                 AbortIO(ReadBuffer -> SerialRequest);
  1113.  
  1114.             WaitIO(ReadBuffer -> SerialRequest);
  1115.         }
  1116.  
  1117.         FreeVec(ReadBuffer);
  1118.     }
  1119.     else
  1120.         DeleteSerialBuffer(ReadBuffer);
  1121.  
  1122.     if(ConsoleWritePort)
  1123.         DeleteMsgPort(ConsoleWritePort);
  1124.  
  1125.     if(ConsoleReadPort)
  1126.         DeleteMsgPort(ConsoleReadPort);
  1127.  
  1128.     if(WritePort)
  1129.         DeleteMsgPort(WritePort);
  1130.  
  1131.     if(ReadPort)
  1132.         DeleteMsgPort(ReadPort);
  1133.  
  1134.     if(TimeRequest)
  1135.     {
  1136.         if(TimeRequest -> tr_node . io_Device)
  1137.             CloseDevice(TimeRequest);
  1138.  
  1139.         DeleteIORequest(TimeRequest);
  1140.     }
  1141.  
  1142.     if(TimePort)
  1143.         DeleteMsgPort(TimePort);
  1144.  
  1145.     if(UtilityBase)
  1146.         CloseLibrary(UtilityBase);
  1147.  
  1148.     if(AslBase)
  1149.         CloseLibrary(AslBase);
  1150.  
  1151.     if(GadToolsBase)
  1152.         CloseLibrary(GadToolsBase);
  1153.  
  1154.     if(GfxBase)
  1155.         CloseLibrary(GfxBase);
  1156.  
  1157.     if(IntuitionBase)
  1158.         CloseLibrary(IntuitionBase);
  1159.  
  1160.     if(RendezvousData)
  1161.     {
  1162.         (*RendezvousSemaphore -> rs_Logoff)(RendezvousData);
  1163.  
  1164.         RendezvousData = NULL;
  1165.     }
  1166.  
  1167.     if(RendezvousSemaphore)
  1168.     {
  1169.         ReleaseSemaphore(RendezvousSemaphore);
  1170.  
  1171.         RendezvousSemaphore = NULL;
  1172.     }
  1173. }
  1174.  
  1175.     /* ConPutc():
  1176.      *
  1177.      *    Output a single character.
  1178.      */
  1179.  
  1180. VOID __stdargs
  1181. ConPutc(struct IOStdReq *Request,UBYTE Char)
  1182. {
  1183.     Request -> io_Command    = CMD_WRITE;
  1184.     Request -> io_Data    = &Char;
  1185.     Request -> io_Length    = 1;
  1186.  
  1187.     DoIO(Request);
  1188. }
  1189.  
  1190.     /* ConPuts():
  1191.      *
  1192.      *    Output a string.
  1193.      */
  1194.  
  1195. VOID
  1196. ConPuts(struct IOStdReq *Request,STRPTR String)
  1197. {
  1198.     Request -> io_Command    = CMD_WRITE;
  1199.     Request -> io_Data    = String;
  1200.     Request -> io_Length    = strlen(String);
  1201.  
  1202.     DoIO(Request);
  1203. }
  1204.  
  1205.     /* ConPrintf():
  1206.      *
  1207.      *    Formatted console output.
  1208.      */
  1209.  
  1210. VOID __stdargs
  1211. ConPrintf(struct IOStdReq *Request,STRPTR Format,...)
  1212. {
  1213.     STATIC UBYTE Buffer[512];
  1214.  
  1215.     va_list VarArgs;
  1216.  
  1217.     va_start(VarArgs,Format);
  1218.     vsprintf(Buffer,Format,VarArgs);
  1219.     va_end(VarArgs);
  1220.  
  1221.     Request -> io_Command    = CMD_WRITE;
  1222.     Request -> io_Data    = Buffer;
  1223.     Request -> io_Length    = strlen(Buffer);
  1224.  
  1225.     DoIO(Request);
  1226. }
  1227.  
  1228.     /* ConMove():
  1229.      *
  1230.      *    Move the cursor to a new position.
  1231.      */
  1232.  
  1233. VOID
  1234. ConMove(struct IOStdReq *Request,LONG x,LONG y)
  1235. {
  1236.     ConPrintf(Request,"\33[%ld;%ldH",y,x);
  1237. }
  1238.  
  1239.     /* ConClear():
  1240.      *
  1241.      *    Clear the console window.
  1242.      */
  1243.  
  1244. VOID
  1245. ConClear(struct IOStdReq *Request)
  1246. {
  1247.     struct ConUnit *ConUnit = (struct ConUnit *)Request -> io_Device;
  1248.     LONG x,y;
  1249.  
  1250.     x = ConUnit -> cu_XCCP;
  1251.     y = ConUnit -> cu_YCCP;
  1252.  
  1253.     ConPrintf(Request,"\f\33[%ld;%ldH",y,x);
  1254. }
  1255.  
  1256.     /* ConGetKey():
  1257.      *
  1258.      *    Read a character from a console window.
  1259.      */
  1260.  
  1261. int
  1262. ConGetKey()
  1263. {
  1264.     if(ConsoleReady)
  1265.     {
  1266.         int Result = ConsoleChar;
  1267.  
  1268.         ConsoleReady = FALSE;
  1269.  
  1270.         ConsoleReadRequest -> io_Command    = CMD_READ;
  1271.         ConsoleReadRequest -> io_Data        = &ConsoleChar;
  1272.         ConsoleReadRequest -> io_Length        = 1;
  1273.  
  1274.         ClrSignal(SIG_CONREAD);
  1275.         SendIO(ConsoleReadRequest);
  1276.  
  1277.         return(Result);
  1278.     }
  1279.     else
  1280.     {
  1281.         int Result = 0;
  1282.  
  1283.         if(WindowReady)
  1284.         {
  1285.             struct IntuiMessage *IntuiMessage;
  1286.             ULONG MsgClass;
  1287.             UWORD MsgCode;
  1288.  
  1289.             while(IntuiMessage = (struct IntuiMessage *)GetMsg(LocalWindow -> UserPort))
  1290.             {
  1291.                 MsgClass    = IntuiMessage -> Class;
  1292.                 MsgCode        = IntuiMessage -> Code;
  1293.  
  1294.                 ReplyMsg(IntuiMessage);
  1295.  
  1296.                 if(MsgClass == IDCMP_MENUPICK)
  1297.                 {
  1298.                     struct MenuItem *Item;
  1299.  
  1300.                     while(MsgCode != MENUNULL)
  1301.                     {
  1302.                         if(Item = ItemAddress(Menu,MsgCode))
  1303.                         {
  1304.                             if(MENU_USERDATA(Item))
  1305.                             {
  1306.                                 if(!Result)
  1307.                                     Result = (int)MENU_USERDATA(Item);
  1308.                             }
  1309.  
  1310.                             MsgCode = Item -> NextSelect;
  1311.                         }
  1312.                         else
  1313.                             break;
  1314.                     }
  1315.                 }
  1316.             }
  1317.  
  1318.             WindowReady = FALSE;
  1319.         }
  1320.  
  1321.         return(Result);
  1322.     }
  1323. }
  1324.  
  1325.     /* ConScanKey():
  1326.      *
  1327.      *    Check for a keyboard event.
  1328.      */
  1329.  
  1330. int
  1331. ConScanKey()
  1332. {
  1333.     if(ConsoleReady || WindowReady)
  1334.         return(1);
  1335.     else
  1336.     {
  1337.         int Result = 0;
  1338.  
  1339.         if(CheckSignal(SIG_WINDOW))
  1340.         {
  1341.             WindowReady = TRUE;
  1342.  
  1343.             Result = 1;
  1344.         }
  1345.  
  1346.         if(CheckIO(ConsoleReadRequest))
  1347.         {
  1348.             if(!WaitIO(ConsoleReadRequest))
  1349.             {
  1350.                 ConsoleReady = TRUE;
  1351.  
  1352.                 return(1);
  1353.             }
  1354.             else
  1355.             {
  1356.                 ConsoleReadRequest -> io_Command    = CMD_READ;
  1357.                 ConsoleReadRequest -> io_Data        = &ConsoleChar;
  1358.                 ConsoleReadRequest -> io_Length        = 1;
  1359.  
  1360.                 ClrSignal(SIG_CONREAD);
  1361.                 SendIO(ConsoleReadRequest);
  1362.             }
  1363.         }
  1364.  
  1365.         return(Result);
  1366.     }
  1367.  
  1368.     return(0);
  1369. }
  1370.  
  1371.     /* dtr_out(byte flag):
  1372.      *
  1373.      *    If flag == 0 -> drop DTR signal, else set it.
  1374.      */
  1375.  
  1376. VOID
  1377. dtr_out(byte flag)
  1378. {
  1379.     if(!flag && !RendezvousData)
  1380.     {
  1381.         if(ThisBuffer -> IsBusy)
  1382.         {
  1383.             WaitIO(ThisBuffer -> SerialRequest);
  1384.  
  1385.             ThisBuffer -> IsBusy        = FALSE;
  1386.             ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1387.         }
  1388.  
  1389.         if(ReadBuffer -> IsBusy)
  1390.         {
  1391.             if(!CheckIO(ReadBuffer -> SerialRequest))
  1392.                 AbortIO(ReadBuffer -> SerialRequest);
  1393.  
  1394.             WaitIO(ReadBuffer -> SerialRequest);
  1395.  
  1396.             ReadBuffer -> IsBusy        = FALSE;
  1397.             ReadBuffer -> SerialFilled    = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1398.             ReadBuffer -> SerialIndex    = ReadBuffer -> SerialBuffer;
  1399.  
  1400.             ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  1401.  
  1402.             DoIO(ReadBuffer -> SerialRequest);
  1403.  
  1404.             if(ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1405.             {
  1406.                 LONG Size = ReadBuffer -> SerialSize - ReadBuffer -> SerialFilled;
  1407.  
  1408.                 if(Size > 0)
  1409.                 {
  1410.                     if(Size > ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1411.                         Size = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1412.  
  1413.                     ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  1414.                     ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer + ReadBuffer -> SerialFilled;
  1415.                     ReadBuffer -> SerialRequest -> IOSer . io_Length    = Size;
  1416.  
  1417.                     DoIO(ReadBuffer -> SerialRequest);
  1418.  
  1419.                     ReadBuffer -> SerialFilled += ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1420.                 }
  1421.             }
  1422.         }
  1423.  
  1424.         CloseDevice(ReadBuffer -> SerialRequest);
  1425.  
  1426.         TimeRequest -> tr_node . io_Command    = TR_ADDREQUEST;
  1427.         TimeRequest -> tr_time . tv_secs    = 1;
  1428.         TimeRequest -> tr_time . tv_micro    = 0;
  1429.  
  1430.         DoIO(TimeRequest);
  1431.  
  1432.         if(OpenDevice(device,port,ReadBuffer -> SerialRequest,NULL))
  1433.         {
  1434.             CloseAll();
  1435.  
  1436.             exit(10);
  1437.         }
  1438.         else
  1439.         {
  1440.             ReadBuffer -> SerialRequest -> io_Baud        = ThisBuffer -> SerialRequest -> io_Baud;
  1441.             ReadBuffer -> SerialRequest -> io_ReadLen    = ThisBuffer -> SerialRequest -> io_ReadLen;
  1442.             ReadBuffer -> SerialRequest -> io_WriteLen    = ThisBuffer -> SerialRequest -> io_WriteLen;
  1443.             ReadBuffer -> SerialRequest -> io_SerFlags    = ThisBuffer -> SerialRequest -> io_SerFlags;
  1444.  
  1445.             ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_SETPARAMS;
  1446.  
  1447.             DoIO(ReadBuffer -> SerialRequest);
  1448.  
  1449.             CopyMem(ReadBuffer -> SerialRequest,ThisBuffer -> SerialRequest,sizeof(struct IOExtSer));
  1450.  
  1451.             ThisBuffer -> SerialRequest -> IOSer . io_Message . mn_ReplyPort = WritePort;
  1452.  
  1453.             CopyMem(ReadBuffer -> SerialRequest,NextBuffer -> SerialRequest,sizeof(struct IOExtSer));
  1454.  
  1455.             NextBuffer -> SerialRequest -> IOSer . io_Message . mn_ReplyPort = WritePort;
  1456.         }
  1457.     }
  1458. }
  1459.  
  1460.     /* com_flow(byte flags):
  1461.      *
  1462.      *    The bit mask `flags' determines the style(s) of
  1463.      *    handshaking:
  1464.      *
  1465.      *    if (flags & 9) -> enable xON/xOFF software handshaking,
  1466.      *    if (flags & 2) -> enable RTS/CTS hardware handshaking
  1467.      */
  1468.  
  1469. VOID
  1470. com_flow(byte flags)
  1471. {
  1472.     if(ThisBuffer -> IsBusy)
  1473.     {
  1474.         WaitIO(ThisBuffer -> SerialRequest);
  1475.  
  1476.         ThisBuffer -> IsBusy        = FALSE;
  1477.         ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1478.     }
  1479.  
  1480.     if(ReadBuffer -> IsBusy)
  1481.     {
  1482.         if(!CheckIO(ReadBuffer -> SerialRequest))
  1483.             AbortIO(ReadBuffer -> SerialRequest);
  1484.  
  1485.         WaitIO(ReadBuffer -> SerialRequest);
  1486.  
  1487.         ReadBuffer -> IsBusy        = FALSE;
  1488.         ReadBuffer -> SerialFilled    = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1489.         ReadBuffer -> SerialIndex    = ReadBuffer -> SerialBuffer;
  1490.  
  1491.         ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  1492.  
  1493.         DoIO(ReadBuffer -> SerialRequest);
  1494.  
  1495.         if(ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1496.         {
  1497.             LONG Size = ReadBuffer -> SerialSize - ReadBuffer -> SerialFilled;
  1498.  
  1499.             if(Size > 0)
  1500.             {
  1501.                 if(Size > ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1502.                     Size = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1503.  
  1504.                 ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  1505.                 ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer + ReadBuffer -> SerialFilled;
  1506.                 ReadBuffer -> SerialRequest -> IOSer . io_Length    = Size;
  1507.  
  1508.                 DoIO(ReadBuffer -> SerialRequest);
  1509.  
  1510.                 ReadBuffer -> SerialFilled += ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1511.             }
  1512.         }
  1513.     }
  1514.  
  1515.     if(flags & 2)
  1516.         ReadBuffer -> SerialRequest -> io_SerFlags |= SERF_7WIRE;
  1517.     else
  1518.         ReadBuffer -> SerialRequest -> io_SerFlags &= ~SERF_7WIRE;
  1519.  
  1520.     if(flags & 9)
  1521.         ReadBuffer -> SerialRequest -> io_SerFlags &= ~SERF_XDISABLED;
  1522.     else
  1523.         ReadBuffer -> SerialRequest -> io_SerFlags |= SERF_XDISABLED;
  1524.  
  1525.     ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_SETPARAMS;
  1526.  
  1527.     DoIO(ReadBuffer -> SerialRequest);
  1528.  
  1529.     ThisBuffer -> SerialRequest -> io_SerFlags = ReadBuffer -> SerialRequest -> io_SerFlags;
  1530.     NextBuffer -> SerialRequest -> io_SerFlags = ReadBuffer -> SerialRequest -> io_SerFlags;
  1531. }
  1532.  
  1533.     /* com_setspeed(word speed):
  1534.      *
  1535.      *    Set the transfer speed (in bits/second).
  1536.      */
  1537.  
  1538. VOID
  1539. com_setspeed(word speed)
  1540. {
  1541.     if(ThisBuffer -> IsBusy)
  1542.     {
  1543.         WaitIO(ThisBuffer -> SerialRequest);
  1544.  
  1545.         ThisBuffer -> IsBusy        = FALSE;
  1546.         ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1547.     }
  1548.  
  1549.     if(ReadBuffer -> IsBusy)
  1550.     {
  1551.         if(!CheckIO(ReadBuffer -> SerialRequest))
  1552.             AbortIO(ReadBuffer -> SerialRequest);
  1553.  
  1554.         WaitIO(ReadBuffer -> SerialRequest);
  1555.  
  1556.         ReadBuffer -> IsBusy        = FALSE;
  1557.         ReadBuffer -> SerialFilled    = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1558.         ReadBuffer -> SerialIndex    = ReadBuffer -> SerialBuffer;
  1559.  
  1560.         ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  1561.  
  1562.         DoIO(ReadBuffer -> SerialRequest);
  1563.  
  1564.         if(ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1565.         {
  1566.             LONG Size = ReadBuffer -> SerialSize - ReadBuffer -> SerialFilled;
  1567.  
  1568.             if(Size > 0)
  1569.             {
  1570.                 if(Size > ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1571.                     Size = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1572.  
  1573.                 ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  1574.                 ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer + ReadBuffer -> SerialFilled;
  1575.                 ReadBuffer -> SerialRequest -> IOSer . io_Length    = Size;
  1576.  
  1577.                 DoIO(ReadBuffer -> SerialRequest);
  1578.  
  1579.                 ReadBuffer -> SerialFilled += ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1580.             }
  1581.         }
  1582.     }
  1583.  
  1584.     ReadBuffer -> SerialRequest -> io_Baud = speed;
  1585.  
  1586.     if(parity)
  1587.     {
  1588.         ReadBuffer -> SerialRequest -> io_ReadLen = ReadBuffer -> SerialRequest -> io_WriteLen = 7;
  1589.         ReadBuffer -> SerialRequest -> io_SerFlags |= SERF_PARTY_ON;
  1590.     }
  1591.     else
  1592.     {
  1593.         ReadBuffer -> SerialRequest -> io_ReadLen = ReadBuffer -> SerialRequest -> io_WriteLen = 8;
  1594.         ReadBuffer -> SerialRequest -> io_SerFlags &= ~SERF_PARTY_ON;
  1595.     }
  1596.  
  1597.     ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_SETPARAMS;
  1598.  
  1599.     DoIO(ReadBuffer -> SerialRequest);
  1600.  
  1601.     ThisBuffer -> SerialRequest -> io_Baud        = ReadBuffer -> SerialRequest -> io_Baud;
  1602.     ThisBuffer -> SerialRequest -> io_ReadLen    = ReadBuffer -> SerialRequest -> io_ReadLen;
  1603.     ThisBuffer -> SerialRequest -> io_WriteLen    = ReadBuffer -> SerialRequest -> io_WriteLen;
  1604.     ThisBuffer -> SerialRequest -> io_SerFlags    = ReadBuffer -> SerialRequest -> io_SerFlags;
  1605.  
  1606.     NextBuffer -> SerialRequest -> io_Baud        = ReadBuffer -> SerialRequest -> io_Baud;
  1607.     NextBuffer -> SerialRequest -> io_ReadLen    = ReadBuffer -> SerialRequest -> io_ReadLen;
  1608.     NextBuffer -> SerialRequest -> io_WriteLen    = ReadBuffer -> SerialRequest -> io_WriteLen;
  1609.     NextBuffer -> SerialRequest -> io_SerFlags    = ReadBuffer -> SerialRequest -> io_SerFlags;
  1610. }
  1611.  
  1612.     /* com_putblock(byte *s,word len):
  1613.      *
  1614.      *    Send a data block asynchronously.
  1615.      */
  1616.  
  1617. VOID
  1618. com_putblock(byte *s,word len)
  1619. {
  1620.     struct SerialBuffer *Swap = ThisBuffer;
  1621.  
  1622.     if(ThisBuffer -> IsBusy)
  1623.         WaitIO(ThisBuffer -> SerialRequest);
  1624.     else
  1625.     {
  1626.         if(ThisBuffer -> SerialIndex > ThisBuffer -> SerialBuffer)
  1627.         {
  1628.             ThisBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  1629.             ThisBuffer -> SerialRequest -> IOSer . io_Data        = ThisBuffer -> SerialBuffer;
  1630.             ThisBuffer -> SerialRequest -> IOSer . io_Length    = ThisBuffer -> SerialIndex - ThisBuffer -> SerialBuffer;
  1631.  
  1632.             DoIO(ThisBuffer -> SerialRequest);
  1633.         }
  1634.     }
  1635.  
  1636.     ThisBuffer -> IsBusy        = FALSE;
  1637.     ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1638.  
  1639.     ThisBuffer = NextBuffer;
  1640.     NextBuffer = Swap;
  1641.  
  1642.     if(ThisBuffer -> SerialIndex > ThisBuffer -> SerialBuffer)
  1643.     {
  1644.         ThisBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  1645.         ThisBuffer -> SerialRequest -> IOSer . io_Data        = ThisBuffer -> SerialBuffer;
  1646.         ThisBuffer -> SerialRequest -> IOSer . io_Length    = ThisBuffer -> SerialIndex - ThisBuffer -> SerialBuffer;
  1647.  
  1648.         DoIO(ThisBuffer -> SerialRequest);
  1649.     }
  1650.  
  1651.     ThisBuffer -> IsBusy        = FALSE;
  1652.     ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1653.  
  1654.     while(len > 2 * ThisBuffer -> SerialSize)
  1655.     {
  1656.         ThisBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  1657.         ThisBuffer -> SerialRequest -> IOSer . io_Data        = s;
  1658.         ThisBuffer -> SerialRequest -> IOSer . io_Length    = ThisBuffer -> SerialSize;
  1659.  
  1660.         s    += ThisBuffer -> SerialSize;
  1661.         len    -= ThisBuffer -> SerialSize;
  1662.  
  1663.         DoIO(ThisBuffer -> SerialRequest);
  1664.     }
  1665.  
  1666.     CopyMem(s,ThisBuffer -> SerialBuffer,MIN(len,ThisBuffer -> SerialSize));
  1667.  
  1668.     ThisBuffer -> IsBusy                    = TRUE;
  1669.     ThisBuffer -> SerialIndex                = ThisBuffer -> SerialBuffer + MIN(len,ThisBuffer -> SerialSize);
  1670.     ThisBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  1671.     ThisBuffer -> SerialRequest -> IOSer . io_Data        = ThisBuffer -> SerialBuffer;
  1672.     ThisBuffer -> SerialRequest -> IOSer . io_Length    = MIN(len,ThisBuffer -> SerialSize);
  1673.  
  1674.     len    -= ThisBuffer -> SerialRequest -> IOSer . io_Length;
  1675.     s    += ThisBuffer -> SerialRequest -> IOSer . io_Length;
  1676.  
  1677.     ClrSignal(SIG_SERWRITE);
  1678.     SendIO(ThisBuffer -> SerialRequest);
  1679.  
  1680.     if(len > 0)
  1681.     {
  1682.         CopyMem(s,NextBuffer -> SerialBuffer,len);
  1683.  
  1684.         NextBuffer -> SerialIndex = NextBuffer -> SerialBuffer + len;
  1685.     }
  1686. }
  1687.  
  1688.     /* breakfunc():
  1689.      *
  1690.      *    Cleanup routine for SAS/C.
  1691.      */
  1692.  
  1693. static int
  1694. breakfunc(void)
  1695. {
  1696.     CloseAll();
  1697.  
  1698.     return(1);
  1699. }
  1700.  
  1701.     /* sys_init(VOID):
  1702.      *
  1703.      *    Initialize this driver implementation.
  1704.      */
  1705.  
  1706. VOID
  1707. sys_init(VOID)
  1708. {
  1709.     if(!OpenAll(device,port))
  1710.     {
  1711.         CloseAll();
  1712.  
  1713.         endprog(2);
  1714.     }
  1715.  
  1716.     onbreak(breakfunc);
  1717. }
  1718.  
  1719.     /* sys_reset(VOID):
  1720.      *
  1721.      *    Perform cleanup for this driver implementation.
  1722.      */
  1723.  
  1724. VOID
  1725. sys_reset(VOID)
  1726. {
  1727.     CloseAll();
  1728. }
  1729.  
  1730.     /* sys_idle(VOID):
  1731.      *
  1732.      *    This routine gets called when the system is idle.
  1733.      *    That's a nice one. We are supposed to call the
  1734.      *    system scheduler, etc.
  1735.      */
  1736.  
  1737. VOID
  1738. sys_idle(VOID)
  1739. {
  1740.     ULONG Signals;
  1741.  
  1742.     if(ReadBuffer -> SerialFilled <= 0 && !ReadBuffer -> IsBusy)
  1743.     {
  1744.         ReadBuffer -> IsBusy                    = TRUE;
  1745.         ReadBuffer -> SerialIndex                = ReadBuffer -> SerialBuffer;
  1746.         ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  1747.         ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer;
  1748.         ReadBuffer -> SerialRequest -> IOSer . io_Length    = 1;
  1749.  
  1750.         ClrSignal(SIG_SERREAD);
  1751.         SendIO(ReadBuffer -> SerialRequest);
  1752.     }
  1753.  
  1754.     TimeRequest -> tr_node . io_Command    = TR_ADDREQUEST;
  1755.     TimeRequest -> tr_time . tv_secs    = 1;
  1756.     TimeRequest -> tr_time . tv_micro    = 0;
  1757.  
  1758.     ClrSignal(SIG_TIMER);
  1759.     SendIO(TimeRequest);
  1760.  
  1761.     Signals = Wait(SIG_SERREAD | SIG_SERWRITE | SIG_CONREAD | SIG_WINDOW | SIG_TIMER);
  1762.  
  1763.     if(!(Signals & SIG_TIMER))
  1764.     {
  1765.         if(!CheckIO(TimeRequest))
  1766.             AbortIO(TimeRequest);
  1767.     }
  1768.  
  1769.     WaitIO(TimeRequest);
  1770.  
  1771.     if(Signals & SIG_SERREAD)
  1772.     {
  1773.         WaitIO(ReadBuffer -> SerialRequest);
  1774.  
  1775.         ReadBuffer -> IsBusy        = FALSE;
  1776.         ReadBuffer -> SerialFilled    = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1777.         ReadBuffer -> SerialIndex    = ReadBuffer -> SerialBuffer;
  1778.  
  1779.         ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  1780.  
  1781.         DoIO(ReadBuffer -> SerialRequest);
  1782.  
  1783.         if(ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1784.         {
  1785.             LONG Size = ReadBuffer -> SerialSize - ReadBuffer -> SerialFilled;
  1786.  
  1787.             if(Size > 0)
  1788.             {
  1789.                 if(Size > ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1790.                     Size = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1791.  
  1792.                 ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  1793.                 ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer + ReadBuffer -> SerialFilled;
  1794.                 ReadBuffer -> SerialRequest -> IOSer . io_Length    = Size;
  1795.  
  1796.                 DoIO(ReadBuffer -> SerialRequest);
  1797.  
  1798.                 ReadBuffer -> SerialFilled += ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1799.             }
  1800.         }
  1801.     }
  1802.  
  1803.     if(Signals & SIG_SERWRITE)
  1804.     {
  1805.         struct SerialBuffer *Swap = ThisBuffer;
  1806.  
  1807.         WaitIO(ThisBuffer -> SerialRequest);
  1808.  
  1809.         ThisBuffer -> IsBusy        = FALSE;
  1810.         ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1811.  
  1812.         ThisBuffer = NextBuffer;
  1813.         NextBuffer = Swap;
  1814.     }
  1815.  
  1816.     if(Signals & SIG_CONREAD)
  1817.     {
  1818.         WaitIO(ConsoleReadRequest);
  1819.  
  1820.         ConsoleReady = TRUE;
  1821.     }
  1822.  
  1823.     if(Signals & SIG_WINDOW)
  1824.         WindowReady = TRUE;
  1825. }
  1826.  
  1827.     /* com_outfull(VOID):
  1828.      *
  1829.      *    Return number of bytes still to be transferred.
  1830.      */
  1831.  
  1832. int
  1833. com_outfull(VOID)
  1834. {
  1835.     return(ThisBuffer -> SerialIndex - ThisBuffer -> SerialBuffer + NextBuffer -> SerialIndex - NextBuffer -> SerialBuffer);
  1836. }
  1837.  
  1838.     /* carrier(VOID):
  1839.      *
  1840.      *    Return current carrier status.
  1841.      */
  1842.  
  1843. int
  1844. carrier(VOID)
  1845. {
  1846.     if(nocarrier)
  1847.         return(1);
  1848.     else
  1849.     {
  1850.         if(!ThisBuffer -> IsBusy)
  1851.         {
  1852.             ThisBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  1853.  
  1854.             DoIO(ThisBuffer -> SerialRequest);
  1855.  
  1856.             if(ThisBuffer -> SerialRequest -> io_Status & CIAF_COMCD)
  1857.                 return(0);
  1858.             else
  1859.                 return(1);
  1860.         }
  1861.         else
  1862.         {
  1863.             NextBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  1864.  
  1865.             DoIO(NextBuffer -> SerialRequest);
  1866.  
  1867.             if(NextBuffer -> SerialRequest -> io_Status & CIAF_COMCD)
  1868.                 return(0);
  1869.             else
  1870.                 return(1);
  1871.         }
  1872.     }
  1873. }
  1874.  
  1875.     /* com_flush(VOID):
  1876.      *
  1877.      *    Make sure all pending data gets written.
  1878.      */
  1879.  
  1880. VOID
  1881. com_flush(VOID)
  1882. {
  1883.     if(ThisBuffer -> IsBusy)
  1884.     {
  1885.         WaitIO(ThisBuffer -> SerialRequest);
  1886.  
  1887.         ThisBuffer -> IsBusy        = FALSE;
  1888.         ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1889.     }
  1890.  
  1891.     if(NextBuffer -> SerialIndex > NextBuffer -> SerialBuffer)
  1892.     {
  1893.         NextBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  1894.         NextBuffer -> SerialRequest -> IOSer . io_Data        = NextBuffer -> SerialBuffer;
  1895.         NextBuffer -> SerialRequest -> IOSer . io_Length    = NextBuffer -> SerialIndex - NextBuffer -> SerialBuffer;
  1896.  
  1897.         DoIO(NextBuffer -> SerialRequest);
  1898.  
  1899.         NextBuffer -> SerialIndex = NextBuffer -> SerialBuffer;
  1900.     }
  1901. }
  1902.  
  1903.     /* com_putbyte(byte c):
  1904.      *
  1905.      *    Transmit a single byte, queueing it if necessary.
  1906.      */
  1907.  
  1908. VOID
  1909. com_putbyte(byte c)
  1910. {
  1911.     if(ThisBuffer -> IsBusy)
  1912.     {
  1913.         if(NextBuffer -> SerialIndex + 1 >= NextBuffer -> SerialTop)
  1914.         {
  1915.             struct SerialBuffer *Swap = ThisBuffer;
  1916.  
  1917.             WaitIO(ThisBuffer -> SerialRequest);
  1918.  
  1919.             ThisBuffer -> IsBusy        = FALSE;
  1920.             ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1921.  
  1922.             ThisBuffer = NextBuffer;
  1923.             NextBuffer = Swap;
  1924.  
  1925.             ThisBuffer -> IsBusy                    = TRUE;
  1926.             ThisBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  1927.             ThisBuffer -> SerialRequest -> IOSer . io_Data        = ThisBuffer -> SerialBuffer;
  1928.             ThisBuffer -> SerialRequest -> IOSer . io_Length    = ThisBuffer -> SerialIndex - ThisBuffer -> SerialBuffer;
  1929.  
  1930.             ClrSignal(SIG_SERWRITE);
  1931.             SendIO(ThisBuffer -> SerialRequest);
  1932.         }
  1933.  
  1934.         *NextBuffer -> SerialIndex++ = c;
  1935.     }
  1936.     else
  1937.     {
  1938.         if(ThisBuffer -> SerialIndex + 1 < ThisBuffer -> SerialTop)
  1939.         {
  1940.             *ThisBuffer -> SerialIndex++ = c;
  1941.  
  1942.             ThisBuffer -> IsBusy                    = TRUE;
  1943.             ThisBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  1944.             ThisBuffer -> SerialRequest -> IOSer . io_Data        = ThisBuffer -> SerialBuffer;
  1945.             ThisBuffer -> SerialRequest -> IOSer . io_Length    = 1;
  1946.  
  1947.             ClrSignal(SIG_SERWRITE);
  1948.             SendIO(ThisBuffer -> SerialRequest);
  1949.         }
  1950.         else
  1951.         {
  1952.             ThisBuffer -> IsBusy                    = TRUE;
  1953.             ThisBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  1954.             ThisBuffer -> SerialRequest -> IOSer . io_Data        = ThisBuffer -> SerialBuffer;
  1955.             ThisBuffer -> SerialRequest -> IOSer . io_Length    = ThisBuffer -> SerialIndex - ThisBuffer -> SerialBuffer;
  1956.  
  1957.             ClrSignal(SIG_SERWRITE);
  1958.             SendIO(ThisBuffer -> SerialRequest);
  1959.  
  1960.             *NextBuffer -> SerialIndex++ = c;
  1961.         }
  1962.     }
  1963. }
  1964.  
  1965.     /* com_purge(VOID):
  1966.      *
  1967.      *    Clear the read/write buffers.
  1968.      */
  1969.  
  1970. VOID
  1971. com_purge(VOID)
  1972. {
  1973.     if(ThisBuffer -> IsBusy)
  1974.     {
  1975.         if(!CheckIO(ThisBuffer -> SerialRequest))
  1976.             AbortIO(ThisBuffer -> SerialRequest);
  1977.  
  1978.         WaitIO(ThisBuffer -> SerialRequest);
  1979.     }
  1980.  
  1981.     ThisBuffer -> IsBusy        = FALSE;
  1982.     ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1983.  
  1984.     NextBuffer -> IsBusy        = FALSE;
  1985.     NextBuffer -> SerialIndex    = NextBuffer -> SerialBuffer;
  1986.  
  1987.     if(ReadBuffer -> IsBusy)
  1988.     {
  1989.         if(!CheckIO(ReadBuffer -> SerialRequest))
  1990.             AbortIO(ReadBuffer -> SerialRequest);
  1991.  
  1992.         WaitIO(ReadBuffer -> SerialRequest);
  1993.     }
  1994.  
  1995.     ReadBuffer -> IsBusy        = FALSE;
  1996.     ReadBuffer -> SerialIndex    = ReadBuffer -> SerialBuffer;
  1997.     ReadBuffer -> SerialFilled    = 0;
  1998.  
  1999.     ThisBuffer -> SerialRequest -> IOSer . io_Command = CMD_CLEAR;
  2000.     DoIO(ThisBuffer -> SerialRequest);
  2001. }
  2002.  
  2003.     /* com_dump(VOID):
  2004.      *
  2005.      *    Wait for asynchronous write request to terminate.
  2006.      */
  2007.  
  2008. VOID
  2009. com_dump(VOID)
  2010. {
  2011.     com_flush();
  2012. }
  2013.  
  2014.     /* com_getbyte(VOID):
  2015.      *
  2016.      *    Read a single byte from the serial line. If not available,
  2017.      *    return EOF.
  2018.      */
  2019.  
  2020. int
  2021. com_getbyte(VOID)
  2022. {
  2023.     int Result;
  2024.  
  2025.     if(ReadBuffer -> SerialFilled <= 0)
  2026.     {
  2027.         if(ReadBuffer -> IsBusy)
  2028.         {
  2029.             if(!CheckIO(ReadBuffer -> SerialRequest))
  2030.                 return(EOF);
  2031.             else
  2032.                 WaitIO(ReadBuffer -> SerialRequest);
  2033.  
  2034.             ReadBuffer -> IsBusy        = FALSE;
  2035.             ReadBuffer -> SerialFilled    = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  2036.             ReadBuffer -> SerialIndex    = ReadBuffer -> SerialBuffer;
  2037.  
  2038.             ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  2039.  
  2040.             DoIO(ReadBuffer -> SerialRequest);
  2041.  
  2042.             if(ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  2043.             {
  2044.                 LONG Size = ReadBuffer -> SerialSize - ReadBuffer -> SerialFilled;
  2045.  
  2046.                 if(Size > 0)
  2047.                 {
  2048.                     if(Size > ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  2049.                         Size = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  2050.  
  2051.                     ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  2052.                     ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer + ReadBuffer -> SerialFilled;
  2053.                     ReadBuffer -> SerialRequest -> IOSer . io_Length    = Size;
  2054.  
  2055.                     DoIO(ReadBuffer -> SerialRequest);
  2056.  
  2057.                     ReadBuffer -> SerialFilled += ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  2058.                 }
  2059.             }
  2060.         }
  2061.         else
  2062.         {
  2063.             ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  2064.  
  2065.             DoIO(ReadBuffer -> SerialRequest);
  2066.  
  2067.             if(!ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  2068.                 return(EOF);
  2069.             else
  2070.             {
  2071.                 ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  2072.                 ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer;
  2073.                 ReadBuffer -> SerialRequest -> IOSer . io_Length    = MIN(ReadBuffer -> SerialRequest -> IOSer . io_Actual,ReadBuffer -> SerialSize);
  2074.  
  2075.                 DoIO(ReadBuffer -> SerialRequest);
  2076.  
  2077.                 if(!ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  2078.                     return(EOF);
  2079.                 else
  2080.                 {
  2081.                     ReadBuffer -> SerialFilled    = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  2082.                     ReadBuffer -> SerialIndex    = ReadBuffer -> SerialBuffer;
  2083.                 }
  2084.             }
  2085.         }
  2086.     }
  2087.  
  2088.     Result = *ReadBuffer -> SerialIndex++;
  2089.  
  2090.     ReadBuffer -> SerialFilled--;
  2091.  
  2092.     if(ReadBuffer -> SerialFilled <= 0)
  2093.     {
  2094.         ReadBuffer -> IsBusy                    = TRUE;
  2095.         ReadBuffer -> SerialIndex                = ReadBuffer -> SerialBuffer;
  2096.  
  2097.         ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  2098.         ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer;
  2099.         ReadBuffer -> SerialRequest -> IOSer . io_Length    = 1;
  2100.  
  2101.         ClrSignal(SIG_SERREAD);
  2102.         SendIO(ReadBuffer -> SerialRequest);
  2103.     }
  2104.  
  2105.     return(Result);
  2106. }
  2107.  
  2108.     /* setstamp(STRPTR Name,LONG Time):
  2109.      *
  2110.      *    Set time/date of a file.
  2111.      */
  2112.  
  2113. VOID
  2114. setstamp(char *Name,long Time)
  2115. {
  2116.     struct DateStamp    Date;
  2117.     ULONG            Seconds;
  2118.  
  2119.         /* Translate it into an Amiga date. */
  2120.  
  2121.     if(Time > GMT_Offset)
  2122.         Seconds = Time - GMT_Offset;
  2123.     else
  2124.         Seconds = 0;
  2125.  
  2126.     Date . ds_Days        = Seconds / (24 * 60 * 60);
  2127.     Date . ds_Minute    = (Seconds % (24 * 60 * 60)) / 60;
  2128.     Date . ds_Tick        = (Seconds % 60) * TICKS_PER_SECOND;
  2129.  
  2130.     SetFileDate(Name,&Date);
  2131. }
  2132.  
  2133.     /* freespace(STRPTR DrivePath):
  2134.      *
  2135.      *    Get free disk space for specified drive.
  2136.      */
  2137.  
  2138. long
  2139. freespace(char *DrivePath)
  2140. {
  2141.     struct DevProc    *DevProc = GetDeviceProc(DrivePath,NULL);
  2142.     struct DosList    *DosList;
  2143.     BOOL         GoodDevice = FALSE;
  2144.     LONG         Size = (LONG)((ULONG)~0 >> 2);
  2145.  
  2146.     if(!DrivePath)
  2147.         DrivePath = "";
  2148.  
  2149.     if(DosList = LockDosList(LDF_DEVICES | LDF_READ))
  2150.     {
  2151.         while(DosList = NextDosEntry(DosList,LDF_DEVICES))
  2152.         {
  2153.             if(DosList -> dol_Task == DevProc -> dvp_Port)
  2154.             {
  2155.                 struct FileSysStartupMsg *FSSM = (struct FileSysStartupMsg *)BADDR(DosList -> dol_misc . dol_handler . dol_Startup);
  2156.  
  2157.                 if(TypeOfMem(FSSM))
  2158.                 {
  2159.                     struct DosEnvec *DosEnvec = (struct DosEnvec *)BADDR(FSSM -> fssm_Environ);
  2160.                     STRPTR Name = (STRPTR)BADDR(FSSM -> fssm_Device);
  2161.  
  2162.                     if(TypeOfMem(DosEnvec) && TypeOfMem(Name))
  2163.                     {
  2164.                         if(Name[0] > 0 && !Name[(WORD)Name[0] + 1])
  2165.                         {
  2166.                             struct IOStdReq __aligned IORequest;
  2167.  
  2168.                             if(!OpenDevice(Name + 1,FSSM -> fssm_Unit,&IORequest,FSSM -> fssm_Unit))
  2169.                             {
  2170.                                 CloseDevice(&IORequest);
  2171.  
  2172.                                 if(DosEnvec -> de_TableSize > 0 && DosEnvec -> de_LowCyl <= DosEnvec -> de_HighCyl)
  2173.                                     GoodDevice = TRUE;
  2174.                             }
  2175.                         }
  2176.                     }
  2177.                 }
  2178.             }
  2179.         }
  2180.  
  2181.         UnLockDosList(LDF_DEVICES | LDF_READ);
  2182.     }
  2183.  
  2184.     FreeDeviceProc(DevProc);
  2185.  
  2186.     if(GoodDevice)
  2187.     {
  2188.         struct InfoData *InfoData;
  2189.  
  2190.         if(InfoData = (struct InfoData *)AllocVec(sizeof(struct InfoData),MEMF_ANY | MEMF_PUBLIC))
  2191.         {
  2192.             UBYTE NewName[256],*Index;
  2193.             BPTR FileLock;
  2194.  
  2195.             memcpy(NewName,DrivePath,255);
  2196.  
  2197.             NewName[255] = 0;
  2198.  
  2199.             Index = PathPart(NewName);
  2200.  
  2201.             *Index = 0;
  2202.  
  2203.             FileLock = Lock(NewName,ACCESS_READ);
  2204.  
  2205.             if(FileLock)
  2206.             {
  2207.                 if(Info(FileLock,InfoData))
  2208.                     Size = InfoData -> id_BytesPerBlock * (InfoData -> id_NumBlocks - InfoData -> id_NumBlocksUsed);
  2209.  
  2210.                 UnLock(FileLock);
  2211.             }
  2212.  
  2213.             FreeVec(InfoData);
  2214.         }
  2215.     }
  2216.  
  2217.     return(Size);
  2218. }
  2219.  
  2220.     /* ffirst(char *FileSpec):
  2221.      *
  2222.      *    Return name of first file matching the given specs.
  2223.      */
  2224.  
  2225. char *
  2226. ffirst(char *filespec)
  2227. {
  2228.     AnchorUsed = TRUE;
  2229.  
  2230.     if(MatchFirst(filespec,Anchor))
  2231.         return(NULL);
  2232.     else
  2233.         return((char *)Anchor -> ap_Buf);
  2234. }
  2235.  
  2236.     /* fnext(VOID):
  2237.      *
  2238.      *    Return name of next file matching the given specs.
  2239.      */
  2240.  
  2241. char *
  2242. fnext(VOID)
  2243. {
  2244.     AnchorUsed = TRUE;
  2245.  
  2246.     if(MatchNext(Anchor))
  2247.         return(NULL);
  2248.     else
  2249.         return((char *)Anchor -> ap_Buf);
  2250. }
  2251.  
  2252.     /* time(time_t *timeptr):
  2253.      *
  2254.      *    Get the current time.
  2255.      */
  2256.  
  2257. time_t
  2258. time(time_t *timeptr)
  2259. {
  2260.     struct timeval    Now;
  2261.     time_t        CurrentTime;
  2262.  
  2263.         /* If the timer is already available,
  2264.          * just read the time. Otherwise, open what
  2265.          * we need to tell the time.
  2266.          */
  2267.  
  2268.     if(TimerBase)
  2269.         GetSysTime(&Now);
  2270.     else
  2271.         UpdateTime(&Now);
  2272.  
  2273.         /* Determine the current time, taking the time
  2274.          * zone into account.
  2275.          */
  2276.  
  2277.     CurrentTime = (time_t)(Now . tv_secs + GMT_Offset);
  2278.  
  2279.     if(timeptr)
  2280.         *timeptr = CurrentTime;
  2281.  
  2282.     return(CurrentTime);
  2283. }
  2284.  
  2285.     /* localtime(const time_t *t):
  2286.      *
  2287.      *    Convert UTC into local time.
  2288.      */
  2289.  
  2290. struct tm *
  2291. localtime(const time_t *t)
  2292. {
  2293.     STATIC struct tm Time;
  2294.  
  2295.     ULONG            Seconds,
  2296.                 Delta;
  2297.     struct ClockData    ClockData;
  2298.     BOOL            CloseIt = FALSE;
  2299.  
  2300.         /* We need utility.library for the date conversion. */
  2301.  
  2302.     if(!UtilityBase)
  2303.     {
  2304.         if(UtilityBase = OpenLibrary("utility.library",37))
  2305.             CloseIt = TRUE;
  2306.     }
  2307.  
  2308.         /* Any luck? */
  2309.  
  2310.     if(!UtilityBase)
  2311.     {
  2312.         memset(&Time,0,sizeof(struct tm));
  2313.  
  2314.         return(&Time);
  2315.     }
  2316.  
  2317.         /* Update the time data. */
  2318.  
  2319.     if(!TimerBase)
  2320.         UpdateTime(NULL);
  2321.  
  2322.         /* Add the offset. */
  2323.  
  2324.     if(*t < GMT_Offset)
  2325.         Seconds = 0;
  2326.     else
  2327.         Seconds = (ULONG)*t - GMT_Offset;
  2328.  
  2329.         /* Convert the seconds into time data. */
  2330.  
  2331.     Amiga2Date(Seconds,&ClockData);
  2332.  
  2333.         /* Convert the time data. */
  2334.  
  2335.     Time . tm_sec    = ClockData . sec;
  2336.     Time . tm_min    = ClockData . min;
  2337.     Time . tm_hour    = ClockData . hour;
  2338.     Time . tm_mday    = ClockData . mday;
  2339.     Time . tm_mon    = ClockData . month - 1;
  2340.     Time . tm_year    = ClockData . year - 1900;
  2341.     Time . tm_wday    = ClockData . wday;
  2342.  
  2343.         /* No daylight savings time info is provided. */
  2344.  
  2345.     Time . tm_isdst = 0;
  2346.  
  2347.         /* We will need to fill in the yday entry. */
  2348.  
  2349.     ClockData . mday    = 1;
  2350.     ClockData . month    = 1;
  2351.  
  2352.     Delta = Date2Amiga(&ClockData);
  2353.  
  2354.     Time . tm_yday = (Seconds - Delta) / (24 * 60 * 60) + 1;
  2355.  
  2356.         /* Clean up if necessary. */
  2357.  
  2358.     if(CloseIt)
  2359.     {
  2360.         CloseLibrary(UtilityBase);
  2361.  
  2362.         UtilityBase = NULL;
  2363.     }
  2364.  
  2365.     return(&Time);
  2366. }
  2367.  
  2368.     /* stat(const char *file,struct stat *st):
  2369.      *
  2370.      *    Get information on a file.
  2371.      */
  2372.  
  2373. int
  2374. stat(const char *file,struct stat *st)
  2375. {
  2376.     BPTR FileLock;
  2377.  
  2378.         /* Try to get a lock on the file. */
  2379.  
  2380.     if(FileLock = Lock((STRPTR)file,ACCESS_READ))
  2381.     {
  2382.         STATIC char    Volume[256],
  2383.                 Comment[80];
  2384.  
  2385.         struct FileInfoBlock __aligned    FileInfo;
  2386.         struct InfoData __aligned    InfoData;
  2387.  
  2388.             /* Get information on file and filing system. */
  2389.  
  2390.         if(Examine(FileLock,&FileInfo) && Info(FileLock,&InfoData))
  2391.         {
  2392.             unsigned short mode = 0;
  2393.  
  2394.                 /* Try to get the name of the volume. */
  2395.  
  2396.             if(!NameFromLock(FileLock,Volume,256))
  2397.                 Volume[0] = 0;
  2398.             else
  2399.             {
  2400.                 WORD i;
  2401.  
  2402.                     /* Chop off everything after the colon. */
  2403.  
  2404.                 for(i = 0 ; i < 256 ; i++)
  2405.                 {
  2406.                     if(Volume[i] == ':')
  2407.                     {
  2408.                         Volume[i + 1] = 0;
  2409.  
  2410.                         break;
  2411.                     }
  2412.                 }
  2413.             }
  2414.  
  2415.             UnLock(FileLock);
  2416.  
  2417.                 /* Build the protection bits. */
  2418.  
  2419.             if(!(FileInfo . fib_Protection & FIBF_EXECUTE))
  2420.                 mode |= S_IEXECUTE;
  2421.  
  2422.             if(!(FileInfo . fib_Protection & FIBF_DELETE))
  2423.                 mode |= S_IDELETE;
  2424.  
  2425.             if(!(FileInfo . fib_Protection & FIBF_READ))
  2426.                 mode |= S_IREAD;
  2427.  
  2428.             if(!(FileInfo . fib_Protection & FIBF_WRITE))
  2429.                 mode |= S_IWRITE;
  2430.  
  2431.             if(!(FileInfo . fib_Protection & FIBF_ARCHIVE))
  2432.                 mode |= S_IARCHIVE;
  2433.  
  2434.             if(!(FileInfo . fib_Protection & FIBF_PURE))
  2435.                 mode |= S_IPURE;
  2436.  
  2437.             if(!(FileInfo . fib_Protection & FIBF_SCRIPT))
  2438.                 mode |= S_ISCRIPT;
  2439.  
  2440.                 /* Keep the comment. */
  2441.  
  2442.             strcpy(Comment,FileInfo . fib_Comment);
  2443.  
  2444.                 /* Fix the time if necessary. */
  2445.  
  2446.             if(!TimerBase)
  2447.                 UpdateTime(NULL);
  2448.  
  2449.                 /* Fill in the data. */
  2450.  
  2451.             st -> st_mode    = mode;
  2452.             st -> st_ino    = FileInfo . fib_DiskKey;
  2453.             st -> st_dev    = InfoData . id_DiskType;
  2454.             st -> st_rdev    = Volume;
  2455.             st -> st_nlink    = FileInfo . fib_DirEntryType == ST_SOFTLINK || FileInfo . fib_DirEntryType == ST_LINKDIR || FileInfo . fib_DirEntryType == ST_LINKFILE;
  2456.             st -> st_uid    = FileInfo . fib_OwnerUID;
  2457.             st -> st_gid    = FileInfo . fib_OwnerGID;
  2458.             st -> st_size    = FileInfo . fib_Size;
  2459.             st -> st_atime    = GMT_Offset + (FileInfo . fib_Date . ds_Days * 24 * 60 + FileInfo . fib_Date . ds_Minute) * 60 + FileInfo . fib_Date . ds_Tick / TICKS_PER_SECOND;
  2460.             st -> st_mtime    = st -> st_atime;
  2461.             st -> st_ctime    = st -> st_atime;
  2462.             st -> st_type    = FileInfo . fib_DirEntryType;
  2463.             st -> st_comment= Comment;
  2464.  
  2465.                 /* Success. */
  2466.  
  2467.             return(0);
  2468.         }
  2469.  
  2470.         UnLock(FileLock);
  2471.     }
  2472.  
  2473.         /* What else should I choose? */
  2474.  
  2475.     errno = _OSERR = EIO;
  2476.  
  2477.     return(-1);
  2478. }
  2479.